
#pragma once

#include "ql.h"

struct EvalContext;
typedef struct EvalContext EvalContext;

typedef Obj * (* EvalIdHandler)( void * eid_handler_tag, Id * id );

typedef void (* EvalErrorCallback)( EvalContext * eval );


EvalContext *
create_evaluator( AllocContext * alloc_ctx );

/*
 * set identifier's evaluator routines what determines how to handle identifiers evaluation
 * returns previously installed handler
 */
EvalIdHandler
set_id_evaluator_handler( EvalContext * eval, EvalIdHandler eval_id_cb, void * eid_handler_tag );

EvalErrorCallback
set_evaluator_callback( EvalContext * eval, EvalErrorCallback error_cb );

void *
set_evaluator_tag( EvalContext * eval, void * tag );

void *
get_evaluator_tag( EvalContext * eval );

ErrResult
get_evaluator_last_error( EvalContext * eval );

AllocContext *
get_evaluator_allocator( EvalContext * eval );

void
free_evaluator( EvalContext * eval );

/*
 * evaluates the object given and returns the result
 * if error occurs, this function will not handle it, but pass to upper `evaluate' function
 * this function SHALL NOT be called outside list functions handlers, whose are
 * registered by add_functionX routines
 */
Obj *
internal_evaluate( EvalContext * eval, Obj * decl );

/*
 * evaluates the object given and returns the result
 */
Obj *
evaluate( EvalContext * eval, Obj * obj );

/*
 * emits error and exits from evaluate function
 */
void
evaluator_emit_error( EvalContext * rc, ErrResult err );

/*****************************************************************************
 * functions facility
 *****************************************************************************/

typedef Obj * (* FunctionHandler)( void * tag, List * args );


bool
add_function(
    EvalContext *       eval,
    Id *                function_name,
    FunctionHandler     handler
    );

bool
add_function2(
    EvalContext *       eval,
    Id *                function_name,
    FunctionHandler     handler,
    bool                args_evaluation_needed,
    void *              tag
    );

typedef struct FunctionAssoc
{
    /*
     * function's name
     */
    Id *                function_name;

    /*
     * specifies whether or not it is needed
     * to evaluate arguments of the function before calling it
     */
    bool                args_evaluation_needed;

    /*
     * pointer to the function which corresponds to this function identifier
     */
    FunctionHandler     handler;

    /*
     * tag, associated with the function
     */
    void *              tag;
} FunctionAssoc;

FunctionAssoc *
find_function( EvalContext * eval, Id * function_name );
